package app

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"gitee.com/zhucheer/orange/cfg"
	pb "gitee.com/zhucheer/orange/grpc/sweet"
	"gitee.com/zhucheer/orange/internal"
	orangerequest "gitee.com/zhucheer/orange/request"
	"google.golang.org/grpc"
	"io/ioutil"
	"net"
	"net/http"
	"net/http/httptest"
	"strings"
	"time"
)

type orangeGrpcSrv struct {
	pb.UnimplementedOrangeRPCServer
}

var errGrpcNotOpen = errors.New("grpc server not open")

// orangeGrpcSrv_RequestDo 实现请求方法
func (s *orangeGrpcSrv) RequestDo(c context.Context, req *pb.Parameter) (*pb.Response, error) {
	requestPath := strings.TrimRight(req.Uri, "/")
	if requestPath == "" {
		requestPath = "/"
	}
	// 解析header到request
	header := http.Header{}
	for k, v := range req.Header {
		header.Add(k, v)
	}
	//grpc服务请求体默认是json类型
	header.Set("Content-Type", "application/json;charset=UTF-8")
	header.Set("X-MT", methodGRPC)

	// 复刻http方法到grpc, 生成一个默认的http request，response对象
	r, err := http.NewRequest(http.MethodPost, requestPath, ioutil.NopCloser(bytes.NewBuffer(req.Body)))
	if err != nil {
		panic("http request copy failed")
	}
	r.Method = methodGRPC
	r.RequestURI = requestPath
	r.RemoteAddr = header.Get("X-Client-Ip")
	r.Header = header
	resp := httptest.NewRecorder()

	ctx := NewGrpcCtx(context.Background())
	ctx.SetRW(resp, r)
	ctx.OrangeInput = orangerequest.NewInput(r, maxBodySize)
	runTime := time.Now()

	defer httpAfterDo(ctx, runTime)

	httpHandler, httpMiddleware := routers.Find(r.Method, requestPath, ctx)

	routerHandlerFunc(httpHandler, httpMiddleware, ctx)
	return &pb.Response{
		Status: int32(ctx.responseStatus),
		Body:   ctx.responseBody.Bytes(),
	}, nil
}

// GrpcListenAndStart 启动通用grpc服务
func (app *OrangeServer) GrpcListenAndStart() (err error) {
	if app.shuttingDown() {
		return grpc.ErrServerStopped
	}
	var grpcSrv *grpc.Server
	app.grpcListener, grpcSrv = startCopyHttpGrpcSrv()
	if grpcSrv == nil {
		return errGrpcNotOpen
	}

	return grpcSrv.Serve(app.grpcListener)
}

// OrangeServer_GrpcShutDown 关闭grpc服务
func (app *OrangeServer) GrpcShutDown() {
	if app.grpcListener == nil {
		return
	}
	app.grpcListener.Close()
	return
}

// startCopyHttpGrpcSrv 启动grpc服务
// 此grpc服务是对http服务的复刻，可以通过grpc调用http相关的路由注册方法
func startCopyHttpGrpcSrv() (*net.TCPListener, *grpc.Server) {
	grpcAddr := cfg.GetString("app.grpcAddr", cfg.ConfigDef.GetString("app.grpcAddr"))
	grpcPort := cfg.GetInt("app.grpcPort", 0)
	flagPort := cfg.GetIntFlag("grpc")
	if flagPort > 0 {
		grpcPort = flagPort
	}

	// 不开启grpc服务
	if grpcPort == 0 {
		return nil, nil
	}

	bindAddr := fmt.Sprintf("%s:%d", grpcAddr, grpcPort)
	netListen, err := net.Listen("tcp", bindAddr)
	if err != nil {
		panic("grpc open error failed to listen:" + err.Error())
	}
	tcpListener, ok := netListen.(*net.TCPListener)
	if !ok {
		panic("grpc server listener is not tcp listener")
	}

	s := grpc.NewServer()
	pb.RegisterOrangeRPCServer(s, &orangeGrpcSrv{})

	internal.ConsoleLog(fmt.Sprintf("start grpc server bind:%v", bindAddr))
	return tcpListener, s
}
